﻿/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

#include "BurnCtrl.h"
#include <QMessageBox>
#include <QFileInfo>
#include <QDateTime>
#include <QTimer>
#include <functional>
#include <iostream>
#include "BurnDlg/BurnDlg.h"
#include "SecureLink/Channel.h"
#include "Modem/YModem.h"
#include "DiaglogComSetting.h"
#include "../platform/Securec/secinput.h"
#include "RMDA_TIME_STRU.h"
#include "CmdCtrl.h"
using namespace std;
using namespace BurnCtrlWorkerClass;

namespace {
    const int CACHING_TWO_THOUSAND = 20000;
    const int SLEEP_TIME_100 = 100;
    const int SLEEP_TIME_500 = 500;
    const int SLEEP_TIME_1000 = 1000;
    const int DW31_START_CONNECT_TIME_OUT_7MS = 7;
    const int DEFAULT_USB_NUM = 4;
    const int TIMEOUT = 5000;
}

CSLock BurnCtrl::csLock;
QMap<UINT, BurnCtrl *> BurnCtrl::sendCtrlTimerToPoint;
QMap<UINT, const BurnCtrlTimer::TimerInfo *> BurnCtrl::timerToParam;

void BurnCtrl::SlotBurnCtrlCommonTimerHandlerTest()
{
    if (!isWiteThreadAlive) {
        return;
    }
    switch (commonTimerEvent) {
        case TIMER_ID_SEND:
            EnterCSSend();
            SendCtrl();
            LeaveCSSend();
            return;
        case TIMER_ID_UPLOAD_START_TIME:
            SendCtrl();
            return;
        case TIMER_ID_WAIT_HISILICON:
            SetErrorString(*this, tr("Wait connect success flag timeout."));
            break;
        case TIMER_ID_WAIT_RANDOM:
            SetErrorString(*this, tr("Wait random number timeout."));
            break;
        case TIMER_ID_WAIT_SEC_RESULT:
            SetErrorString(*this, tr("Wait check result timeout."));
            break;
        case TIMER_ID_WAIT_BURN_START_C:
            SetErrorString(*this, tr("Wait start flag (C) timeout."));
            break;
        default:
            BurnCtrlCommonTimerHandlerTestSub1();
            return;
    }
}

void BurnCtrl::BurnCtrlCommonTimerHandlerTestSub1()
{
    switch (commonTimerEvent) {
        case TIMER_ID_WAIT_BURN_INIT_ACK:
            SetErrorString(*this, tr("Wait ACK timeout."));
            break;
        case TIMER_ID_WAIT_BURN_INTER_ACK:
            SetErrorString(*this, tr("Sending file timeout."));
            break;
        case TIMER_ID_WAIT_BURN_EOT_C:
            SetErrorString(*this, tr("Wait EOT ACK C timeout."));
            break;
        case TIMER_ID_WAIT_ZERO_ACK:
            SetErrorString(*this, tr("Wait zero ACK timeout."));
            break;
        case TIMER_ID_UPLOAD_COMMON_TIME:
            SetErrorString(*this, tr("Wait next packet timeout."));
            break;
        case TIMER_ID_UPLOAD_RETRY_TIME:
            if (IsNeedRetry()) {
                SendRetryFlag();
                return;
            } else {
                SetErrorString(*this, tr("Wait next packet timeout."));
            }
            break;
        case TIMER_ID_WAIT_SELOADER_ACK_TIME:
            SetErrorString(*this, tr("Wait SELoader ACK timeout."));
            break;
        default:
            BurnCtrlCommonTimerHandlerTestSub2();
            return;
    }
    SetResult(commonTimerEvent);
    AddLog("Timeout event " + QString::number(commonTimerEvent));
    if (isOneTimeBurn != 0) {
        Global::CloseApp(this->result);
    } else {
        ResetByMode();
    }
    return;
}

void BurnCtrl::BurnCtrlCommonTimerHandlerTestSub2()
{
    switch (commonTimerEvent) {
        case TIMER_ID_WAIT_SELOADER_END_ACK_TIME:
            SetErrorString(*this, tr("Wait SELoader End ACK timeout."));
            TimeoutProcess();
            return;
        case TIMER_ID_COMPLITE_TIME:
            SetEditErrorString(IDS_STRING_32879);
            SetErrorString(*this, stringClass.GetIdsString32880());
            SetEditErrorString(IDS_STRING_32879);
            SlotKillAllTimer();
            return;
        case TIMER_ID_WAIT_NEXT_TIME:
            if (isAutoBurn) {
                LeaveCSEdit();
                EnterCSEdit();
                ClearPlainText();
                OutputString(stringClass.GetIdsString32897());
                LeaveCSEdit();
            }
            SlotKillAllTimer();
            StartConnect();
            return;
        case TIMER_ID_CHECK_IF_CONNECT_TIME:
            if (connectConfirmMaxTime <= connectConfirmTime) {
                if (!isResetAfterSuccess) {
                    SetResult(ERR_WAITING);
                }
                AddLog(stringClass.GetIdsString32806());
                if (isOneTimeBurn != 0) {
                    Global::CloseApp(this->result);
                    return;
                }
                ResetByMode();
            } else {
                connectConfirmTime++;
                TimeoutProcess();
            }
            return;
        default:
            return;
    }
}

void BurnCtrl::SetErrorString(BurnCtrl &ctrl, const QString &enStr)
{
    ctrl.SetEditErrorString(enStr);
}

void BurnCtrl::YmodemPrepareIntialPacket(PBYTE &pBurnFileInfo, int &pktLen) // 初始化头包数据
{
    int gPacketLen = 133; // start packet 133 len
    pktLen = gPacketLen;
    // 在内部分配空间，必须传指针的引用.
    pBurnFileInfo = new unsigned char[gPacketLen];
    if (pBurnFileInfo == nullptr) {
        return;
    }
    SecureZeroMemory(pBurnFileInfo, gPacketLen);

    pBurnFileInfo[0] = MODEM_SOH;
    pBurnFileInfo[1] = pkgNum;
    pBurnFileInfo[2] = 0xff - pkgNum; // 第2位固定值
    pkgNum++;

    int gI = 3;
    WORD crc;
    QFileInfo fileInfo(strFilePath);
    strFileName = fileInfo.fileName();
    if (strFileName.length() < 0xfffffff) {
        for (int j = 0; j < strFileName.length(); j++) {
            pBurnFileInfo[gI++] = static_cast<unsigned char>(strFileName[j].toLatin1());
        }
        pBurnFileInfo[gI++] = 0x00;
    }

    fileSize = fileInfo.size();
    strFileSize = QString::number(fileSize);
    if (strFileSize.length() < 0xfffffff) {
        for (int j = 0; j < strFileSize.length(); j++) {
            pBurnFileInfo[gI++] = static_cast<unsigned char>(strFileSize[j].toLatin1());
        }
    }
    crc = YModemClass::YModem::GetCrc(&pBurnFileInfo[3], 128);           // 从第3字节开始计算128字节的crc
    pBurnFileInfo[131] = static_cast<unsigned char>(crc >> 8); // 131为crc高字节，右移8位
    pBurnFileInfo[132] = static_cast<unsigned char>(crc);      // 132为crc低字节
}

void BurnCtrl::ProcessReceiveData(PBYTE data, unsigned int &dataLen)
{
    if (data == nullptr || dataLen > MAX_BUFFER_LEN) {
        return;
    }
    for (unsigned int i = 0; i < dataLen; i++) {
        data[i] = (data[i] == 0 ? ' ' : data[i]);
    }
    QString strData = QString::fromLatin1(reinterpret_cast<CHAR *>(data));
    switch (fsm) {
        case HI_BURN_FSM::FSM_BURN_WAIT_START_C:
            if (DataConvertor::FindChar(data, dataLen, MODEM_C)) { // 检测升级信号并发送头包
                FsmWaitStartC(strData);
            }
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_INIT_ACK:
            if (DataConvertor::FindChar(data, dataLen, MODEM_ACK)) { // 检测确认回复信号并发送文件
                FsmWaitInitAck(strData);
            }
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_INTER_ACK:
            FsmBurnWaitInterAck(data, dataLen, strData);
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_FINAL_ACK:
            if (DataConvertor::FindChar(data, dataLen, MODEM_ACK)) { // 文件传输完毕，发送"EOT"
                FsmWaitFinalAck(strData);
            }
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_EOT_C:
            if (DataConvertor::FindChar(data, dataLen, MODEM_C)) { // 发送全0结束数据包
                FsmWaitEotC(strData);
            }
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_ZERO_ACK:
            if (DataConvertor::FindChar(data, dataLen, MODEM_ACK)) { // 文件传输完毕，发送"EOT"
                FsmWaitZeroAck(strData);
            }
            break;
        case HI_BURN_FSM::FSM_WORK:
            isProcessOk = true;
            if (isExport) {
                Global::CloseApp(this->result);
            }
            break;
        default:
            break;
    }
}

void BurnCtrl::FsmBurnWaitInterAck(const unsigned char *data, const unsigned int &dataLen,
                                   QString &strData)
{
    if (DataConvertor::FindChar(data, dataLen, MODEM_ACK)) { // 监测确认回复信号并继续发送文件
        RmoveTimerKey();
        strData.clear();
        YmodemNextPacket();
    }
}

void BurnCtrl::FsmWaitInitAck(QString &strData)
{
    RmoveTimerKey();
    commonTimerID = 0;
    strData.clear();
    /* CFile::modeRead */
    if (IsEncrypt()) {
        memoryOperation.SetEncrypt(encryptBuffer, encryptBufferLen);
    } else {
        QString cleanPath = QDir::cleanPath(strFilePath);
        if (cleanPath.isEmpty()) {
            SetEditErrorString(stringClass.GetIdsString32809());
            ResetByMode();
            return;
        }
        binFile.setFileName(cleanPath);
        if (binFile.open(QIODevice::ReadOnly | QIODevice::Truncate) == 0) {
            SetEditErrorString(stringClass.GetIdsString32809());
            ResetByMode();
            return;
        }
    }
    progressPos = 0;
    YmodemNextPacket();
}

void BurnCtrl::FsmWaitFinalAck(QString &strData)
{
    RmoveTimerKey();
    strData.clear();
    int pktLen = 1;
    CHAR* pBurnFile = new char[pktLen];
    if (pBurnFile == nullptr) {
        return;
    }
    SecureZeroMemory(pBurnFile, pktLen);
    pBurnFile[0] = MODEM_EOT;
    WriteToPort(pBurnFile, pktLen);
    if (IsEncrypt()) {
        memoryOperation.Init();
    } else if (binFile.isOpen()) {
        binFile.close();
    }
    isProcessOk = true;
    SetFsm(HI_BURN_FSM::FSM_BURN_WAIT_EOT_C);
    SetTimerByFsm();
    if (pBurnFile != nullptr) {
        delete []pBurnFile;
        pBurnFile = nullptr;
    }
}

void BurnCtrl::FsmWaitEotC(QString &strData)
{
    RmoveTimerKey();
    strData.clear();

    int pktLen = 133; // end packet 133 len
    CHAR* pBurnFile = new char[pktLen];
    if (pBurnFile == nullptr) {
        return;
    }
    SecureZeroMemory(pBurnFile, pktLen);

    pBurnFile[0] = MODEM_SOH;
    pBurnFile[1] = 0x00;
    pBurnFile[2] = 0xff; // 第2字节固定含义
    pkgNum++;

    WORD crc = YModemClass::YModem::GetCrc(reinterpret_cast<PBYTE>(&pBurnFile[3]), 128); // 从第3字节开始计算128字节的crc
    pBurnFile[131] = static_cast<unsigned char>(crc >> 8); // 131为crc高字节，右移8位
    pBurnFile[132] = static_cast<unsigned char>(crc);      // 132为crc低字节
    WriteToPort(pBurnFile, pktLen);

    delete []pBurnFile;
    pBurnFile = nullptr;

    isProcessOk = true;
    SetFsm(HI_BURN_FSM::FSM_BURN_WAIT_ZERO_ACK);
    SetTimerByFsm();
}

void BurnCtrl::FsmWaitZeroAck(QString &strData)
{
    RmoveTimerKey();
    strData.clear();
    pkgNum = 0x0;
    SetFsm(HI_BURN_FSM::FSM_WORK);
    isProcessOk = true;
    if (isOneTimeBurn != 0) {
        Global::CloseApp(this->result);
        return;
    }
    if (isAutoBurn && isOneTimeBurn == 0) {
        SetFileInfo(GetFilePath());
        StartConnect();
    }
}

void BurnCtrl::FsmWaitStartC(QString &strData)
{
    RmoveTimerKey();
    strData.clear();
    PBYTE pBurnFileInfo = nullptr;
    int pktLen;
    YmodemPrepareIntialPacket(pBurnFileInfo, pktLen);
    if (pBurnFileInfo == nullptr) {
        return;
    }
    WriteToPort(reinterpret_cast<CHAR *>(pBurnFileInfo), pktLen);
    delete[] pBurnFileInfo;
    SetFsm(HI_BURN_FSM::FSM_BURN_WAIT_INIT_ACK);
    isProcessOk = true;
    SetTimerByFsm();
}

void BurnCtrl::ResetBurnState()
{
    SlotKillAllTimer();
    SetFsm(HI_BURN_FSM::FSM_WORK);
    progressPos = 0;
    sendCtrlCount = 0;
    // 判断烧写文件是否被打开
    if (IsEncrypt()) {
        memoryOperation.Init();
    } else if (binFile.isOpen()) {
        binFile.close();
    }

    pkgNum = 0x0;

    UpdateProgress(0);
}

void BurnCtrl::WriteToPort(const char *data, int len)
{
    if (fsm != HI_BURN_FSM::FSM_NONE) {
        port.WriteToPort(data, len);
    }
}

bool BurnCtrl::UpdateComSetting(UINT mBaud, UINT mDatabits, UINT mStopbits, QSerialPort::Parity mParity, UINT mFlowctrl)
{
    this->baud = mBaud;
    this->parity = mParity;
    this->databits = mDatabits;
    this->stopbits = mStopbits;
    this->flowctrl = mFlowctrl;

    return true;
}

void BurnCtrl::SetIpSetting(QString mIpAddr, UINT mIpPort)
{
    this->ipAddr = mIpAddr;
    this->ipPort = mIpPort;
}

void BurnCtrl::SetPortType(unsigned int type)
{
    port.SetPortIndex(type);
    this->portType = Base::PORT_INDEX(type);
}

void BurnCtrl::GetComSetting(int &mBaud, int &mDatabits, int &mStopbits,
                             QSerialPort::Parity &mParity, int &mFlowctrl) const
{
    mBaud = this->baud;
    mDatabits = this->databits;
    mStopbits = this->stopbits;
    mParity = this->parity;
    mFlowctrl = this->flowctrl;
}

U32 BurnCtrl::GetBurnFileInfo()
{
    if (!isConnect) {
        return ERR_SOP_CPAB_NOT_CONNECT_UE;
    }

    if (GetBurnFsm() >= HI_BURN_FSM::FSM_BURN_WAIT_START_C && GetBurnFsm() <= HI_BURN_FSM::FSM_BURN_WAIT_ZERO_ACK) {
        return ERR_SOP_BUSY;
    }

    if (burnflag) {
        return ERR_SOP_SUCCESS;
    }

    SetFileInfo(GetCurrentFilePath());
    QFileInfo fileInfo(strFilePath);
    strFileName = fileInfo.fileName();
    fileSize = fileInfo.size();
    strFileSize = QString::number(fileSize);
    if (fileSize <= 0) {
        return ERR_SOP_FILE_NOT_FOUND;
    }
    return ERR_SOP_SUCCESS;
}

U32 BurnCtrl::StartBurn()
{
    U32 ret = GetBurnFileInfo();
    if (ret != ERR_SOP_SUCCESS) {
        return ret;
    }

    SetBurnComNum(GetBurnComToStr());
    SetBurnBinFile(infoArray);
    SetBurnStartTime(GetBurnCurrentTime());
    SetFsm(HI_BURN_FSM::FSM_BURN_WAIT_START_C);
    SetProgressRange(0, SHRT_MAX); // 1024 each progress
    SetTimerByFsm();
    return ERR_SOP_SUCCESS;
}

void BurnCtrl::SetProgressRange(int minimum, int maximum)
{
    emit SignalSetProgressRange(minimum, maximum);
}

bool BurnCtrl::ConfigComPort()
{
    if (com == -1 || worker == nullptr) {
        QMessageBox::warning(nullptr, "", stringClass.GetIdsString32899());
        return false;
    } else {
        PortBaseInitStru serialPortInit;
        serialPortInit.pPortOwner = nullptr;
        serialPortInit.portnr = com;
        serialPortInit.baud = baud;
        serialPortInit.parity = parity;
        serialPortInit.databits = databits;
        serialPortInit.stopbits = stopbits;
        serialPortInit.flowctrl = flowctrl;
        serialPortInit.dwCommEvents = commEvents;
        serialPortInit.writebuffersize = CACHING_TWO_THOUSAND; // 2000缓存
        serialPortInit.witeThreadMsgId = WM_COMM_RXCHAR_WITE_THREAD;
        serialPortInit.witeThread = thread;
        serialPortInit.oneTimeReadByte = 30; // 30bytes
        serialPortInit.isForceReadWithSleep = isForceReadWithSleep;
        serialPortInit.forceReadTime = forceReadTime;
        serialPortInit.ipAddr = ipAddr;
        serialPortInit.ipPort = ipPort;
        if (port.InitPort(serialPortInit)) {
            port.StartMonitoring();
            return true;
        } else {
            SetBurnComNum(GetBurnComToStr());
            SetBurnBinFile(infoArray);
            SetResult(ERR_COM_INVALID);
            if (isOneTimeBurn != 0) {
                emit SignalOpenComFail();
            } else {
                QMessageBox::warning(nullptr, "", stringClass.GetIdsString32812().arg(com));
            }
            return false;
        }
    }
}

bool BurnCtrl::ConfigTcpPort()
{
    PortBaseInitStru serialPortInit;
    serialPortInit.pPortOwner = nullptr;
    serialPortInit.portnr = com;
    serialPortInit.baud = baud;
    serialPortInit.parity = parity;
    serialPortInit.databits = databits;
    serialPortInit.stopbits = stopbits;
    serialPortInit.flowctrl = flowctrl;
    serialPortInit.dwCommEvents = commEvents;
    serialPortInit.writebuffersize = CACHING_TWO_THOUSAND; // 2000缓存
    serialPortInit.witeThreadMsgId = WM_COMM_RXCHAR_WITE_THREAD;
    serialPortInit.witeThread = thread;
    serialPortInit.oneTimeReadByte = 30; // 30bytes
    serialPortInit.isForceReadWithSleep = isForceReadWithSleep;
    serialPortInit.forceReadTime = forceReadTime;
    serialPortInit.ipAddr = ipAddr;
    serialPortInit.ipPort = ipPort;
    if (port.InitPort(serialPortInit)) {
        port.StartMonitoring();
        return true;
    } else {
        QString tcpPortString = ipAddr + ":" + QString::number(ipPort);
        SetBurnComNum(tcpPortString);
        SetBurnBinFile(infoArray);
        SetResult(ERR_COM_INVALID);
        QMessageBox::warning(nullptr, "",
            QString(tr("Failed to open %1, please check ip:port is right or is occupied.")).
            arg(tcpPortString));
        return false;
    }
}

bool BurnCtrl::UpdateComSettingWithoutClose()
{
    if (port.IsThreadAlive() == FALSE) {
        return false;
    }
    ErrorSettingCom error = port.InitPortConfigure(stopbits, flowctrl, baud, parity, databits);
    if (error == ErrorSettingCom::ERROR_SETTING_COM_SUCCESS) {
        return true;
    } else {
        QString portErrorStr = tr(" Change the baud rate or check the serial port.");
        if (error == ErrorSettingCom::ERROR_SETTING_COM_BAUDRATE) {
            SetErrorString(*this, tr("The current serial port cannot use the baud rate,") + portErrorStr);
        } else if (error == ErrorSettingCom::ERROR_SETTING_COM_PARITY) {
            SetErrorString(*this, tr("The current serial port cannot use the parity bit,") + portErrorStr);
        } else if (error == ErrorSettingCom::ERROR_SETTING_COM_DATABITS) {
            SetErrorString(*this, tr("The current serial port cannot use the data bits,") + portErrorStr);
        } else if (error == ErrorSettingCom::ERROR_SETTING_COM_STOPBITS) {
            SetErrorString(*this, tr("The current serial port cannot use the stop bits,") + portErrorStr);
        }
        SetFsm(HI_BURN_FSM::FSM_WORK);
        SetResult(ERR_COM_INVALID);
        if (isOneTimeBurn != 0) {
            Global::CloseApp(this->result);
        } else {
            ResetBurnState();
            WifiState();
        }
        return false;
    }
}

U32 BurnCtrl::SendBurnCmd()
{
    return 0;
}

void BurnCtrl::InitBurnCmd() {}

void BurnCtrl::InitBurnCmdByArray(const QMap<int, BIN_INFO> &mInfoArray)
{
    Q_UNUSED(mInfoArray)
}

void BurnCtrl::SetLoaderInfo(QString loaderFile, int loaderSize)
{
    Q_UNUSED(loaderFile)
    Q_UNUSED(loaderSize)
}

BurnCtrl::BurnCtrl(ChipType type, QObject *parent)
    : QObject(parent),
      isOpen(false),
      isConnect(false),
      filePathIndex(0),
      pkgNum(0x0),
      u32DataLen(0),
      fsm(HI_BURN_FSM::FSM_NONE),
      progressPos(0),
      bootType(BOOT_LOADER),
      isGetRandomData(false),
      burnflag(false),
      baud(115200),       // 115200 波特率
      com(-1),
#ifdef IS_PLC // 串口号
      parity(QSerialPort::EvenParity),    // 校验
#else
      parity(QSerialPort::NoParity),
#endif
      databits(8),   // 8 数据位
      stopbits(1),   // 停止位
      flowctrl(0),    // 流控
      ipAddr("0"),
      ipPort(0),
      sendCtrlTimerID(0),
      timerQueue(CreateTimerQueue()),
      sendCtrlCount(0),
      commonTimerID(0),
      sendBurnTimeout(TIMER_ID_WAIT_RANDOM_3921_TIMEOUT),
      ctrlPeriod(10), // 10
      commEvents(EV_RXFLAG | EV_RXCHAR | EV_CTS),
      burnDlg(nullptr),
      isSecConn(false),
      isAutoBurn(false),
      isLoaderDfu(false),
      dfuMode(DfuBurnMode::DFU),
      isAutoDisconnect(false),
      isReopenCom(false),
      isOneTimeBurn(false),
      isResetAfterSuccess(false),
      isSwitchAfterLoader(false),
      ackFlag(0),
      burnCmdIndex(0),
      result(0),
      isProcessOk(false),
      isForceReadWithSleep(true),
      isResultByOwner(false),
      forceReadTime(10), // 10
      retryTime(0),
      connectConfirmSleepTimeout(100), // 100
      connectConfirmWaitTimeout(200), // 200
      connectConfirmMaxTime(1),
      connectConfirmTime(0),
      onlyBurnToolLog(false),
      independent(false),
      totalNum(20), // 20
      numPerLine(10), // 10
      isReset(false),
      isExport(false),
      exportTarget(""),
      exportAddr(""),
      exportSize(""),
      isShutDown(false),
      isWiteThreadAlive(false),
      witeThread(nullptr),
      witeThreadId(0),
      witeThreadMsgId(WM_COMM_RXCHAR_WITE_THREAD),
      isExactTimer(true),
      burnFileSize(0),
      modemPacketSize(MODEM_PACKET_SIZE),
      modemPacketSizeBackup(MODEM_PACKET_SIZE),
      oneBurnTime(0),
      worker(nullptr),
      thread(nullptr),
      startConnectTimer(nullptr),
      commonTimer(nullptr),
      commonTimerEvent(0),
      isOnlyEraseAll(false),
      isEraseMode(0),
      isMultipleBurn(false),
      chipType(type),
      isCancel(FALSE),
      isFirstBurnStart(true),
      optLog(new OperationLog()),
      isEncrypt(false),
      encryptBuffer(nullptr),
      encryptBufferLen(0),
      readEfuse(false),
      startBit(""),
      bitWidth(""),
      chipModel(0),
      transmissionMode(0),
      burnPath(""),
      isReadBack(false),
      isRun(false),
      infoStartAddress(0),
      eraseConfig(0),
      fwpkgVersion("")
{
    for (unsigned long long i = 0; i < sizeof(cDataArray); i++) {
        cDataArray[i] = 0;
    }
    if (type == ChipType::SPARTA || type == ChipType::MELODY || type == ChipType::COMBS25) {
        totalNum = 8;   // 3x协议多烧写个数默认为8个
        numPerLine = 4; // 3x协议多烧写个数默认为4个1行
        modemPacketSize = MODEM_PACKET_SIZEB;
    } else if (type == ChipType::USB4GCAT1 || type == ChipType::USBHI3322) {
        totalNum = DEFAULT_USB_NUM; // USB4GCAT1一拖多烧写默认4个，最多支持16个
        numPerLine = 8; // USB4GCAT1一拖多烧写个数默认8个1行
    } else if (type == ChipType::WIFI4GCAT1) {
        totalNum = 16; // 4GCAT1一拖多烧写默认16个
        numPerLine = 8; // 4GCAT1一拖多烧写个数默认8个1行
    }
    InitializeCriticalSection(&communicationSync);
    InitializeCriticalSection(&csSend);
    InitializeCriticalSection(&csEdit);
    InitializeCriticalSection(&csLog);
    qRegisterMetaType<QTextCharFormat>("QTextCharFormat");
    qRegisterMetaType<WPARAM>("WPARAM");
    qRegisterMetaType<LPARAM>("LPARAM");
    if (product.GetIsProductVersion()) {
        isSwitchAfterLoader = true;
    }

    m_eraseModeStr << stringClass.GetNormal() << stringClass.GetEraseAll() << stringClass.GetNoErase();
}

BurnCtrl::~BurnCtrl()
{
    if (worker != nullptr) {
        delete worker;
        worker = nullptr;
    }
    SlotKillAllTimer();
    isWiteThreadAlive = false;
    port.ClosePort();
    DeleteCriticalSection(&communicationSync);
    if (thread != nullptr) {
        thread->quit();
        thread->wait();
        delete thread;
        thread = nullptr;
    }
    DeleteCriticalSection(&csEdit);
    DeleteCriticalSection(&csSend);
    DeleteCriticalSection(&csLog);
    if (optLog != nullptr) {
        delete optLog;
    }
}

void BurnCtrl::ResetUIAndFSM()
{
    SlotKillAllTimer();
    SetFsm(HI_BURN_FSM::FSM_NONE);
    port.ClosePort();
    isOpen = false;
    isConnect = false;
    u32DataLen = 0;
    SecureZeroMemory(cDataArray, MAX_BUFFER_LEN);
    burnCmdIndex = 0;
    // 判断烧写文件是否被打开
    if (IsEncrypt()) {
        memoryOperation.Init();
    } else if (binFile.isOpen()) {
        binFile.close();
    }

    pkgNum = 0x0;
    retryTime = 0;
    progressPos = 0;
    UpdateProgress(0);
}

void BurnCtrl::SlotKillAllTimer()
{
    // 杀掉所有Timer
    if (startConnectTimer != nullptr) {
        QMetaObject::invokeMethod(startConnectTimer,
                                  std::bind(static_cast<void(QTimer::*)()>(&QTimer::stop), startConnectTimer),
                                  Qt::DirectConnection);
        QThread::msleep(SLEEP_TIME_100);
        delete startConnectTimer;
        startConnectTimer = nullptr;
    }
    if (sendCtrlTimerID != 0) {
        RemoveRunningItem(sendCtrlTimerID);
        RemoveParamPoint(sendCtrlTimerID);
        sendCtrlTimerID = 0;
    }

    if (commonTimer != nullptr) {
        QMetaObject::invokeMethod(commonTimer,
                                  std::bind(static_cast<void(QTimer::*)()>(&QTimer::stop), commonTimer),
                                  Qt::DirectConnection);
        QThread::msleep(SLEEP_TIME_100);
        delete commonTimer;
        commonTimer = nullptr;
    }

    if (commonTimerID != 0) {
        RemoveRunningItem(commonTimerID);
        RemoveParamPoint(commonTimerID);
        commonTimerID = 0;
    }
}

void BurnCtrl::SetShutDown()
{
    isShutDown = true;
}

void BurnCtrl::SendCtrl()
{
}

void BurnCtrl::StartConnectSetting()
{
}

void BurnCtrl::SetComNum(int num)
{
    com = num;
}

void BurnCtrl::RegisteResultEdit(bool isMultiple)
{
    this->isMultipleBurn = isMultiple;
}

void BurnCtrl::OutputString(QString editStr)
{
    if (!isMultipleBurn) {
        InsertPlainText(editStr);
    }

    AddLog(editStr);
    editStr.replace("%", "%%");
}

void BurnCtrl::InsertPlainText(const QString &editStr)
{
    emit SignalInsertPlainText(editStr);
}

void BurnCtrl::ClearPlainText()
{
    emit SignalClearPlainText();
}

void BurnCtrl::ReplacePlainText(const QString &oldText, const QString &newText)
{
    emit SignalReplacePlainText(oldText, newText);
}

void BurnCtrl::MergeCurrentCharFormat(const QTextCharFormat &fmt)
{
    emit SignalMergeCurrentCharFormat(fmt);
}

void BurnCtrl::SetEditErrorString(QString editStr)
{
    editStr = editStr + IDS_STRING_32824;
    OutputString(editStr);
}

void BurnCtrl::ClosePort()
{
    port.ClosePort();
}

bool BurnCtrl::IsComOpen() const
{
    return isOpen;
}

HI_BURN_FSM BurnCtrl::GetBurnFsm() const
{
    return fsm;
}

void CALLBACK BurnCtrl::BurnCtrlCommonTimerHandler(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser,
                                                   DWORD_PTR dw1, DWORD_PTR dw2)
{
    Q_UNUSED(uMsg);
    Q_UNUSED(dw1);
    Q_UNUSED(dw2);
    BurnCtrl *burnCtrl = GetRunningItem(uTimerID);
    if (burnCtrl == nullptr || burnCtrl->isWiteThreadAlive == FALSE) {
        return;
    }
    switch (dwUser) {
        case TIMER_ID_SEND:
            burnCtrl->SendCtrl();
            break;
        default:
            break;
    }
}

void BurnCtrl::SlotBurnCtrlCommonTimerHandler2()
{
    if (!isWiteThreadAlive) {
        return;
    }
    if (!TimerHandle()) {
        return;
    }
    SetResult(commonTimerEvent);
    ResetByMode();
    QString strLog;
    AddLog("Timeout event " + QString::number(commonTimerEvent));
    if (isOneTimeBurn != 0) {
        Global::CloseApp(this->result);
    } else {
        ResetByMode();
    }
    return;
}

bool BurnCtrl::TimerHandle()
{
    switch (commonTimerEvent) {
        case TIMER_ID_UPLOAD_START_TIME:
            SendCtrl();
            return false;
        case TIMER_ID_UPLOAD_RETRY_TIME:
            if (IsNeedRetry()) {
                SendRetryFlag();
                return false;
            } else {
                SetErrorString(*this, "Wait Next Packet overtime");
            }
            break;
        case TIMER_ID_WAIT_NEXT_TIME:
            if (isAutoBurn) {
                LeaveCSEdit();
                EnterCSEdit();
                ClearPlainText();
                OutputString(stringClass.GetIdsString32897());
                LeaveCSEdit();
            }
            SlotKillAllTimer();
            StartConnect();
            return false;
        case TIMER_ID_CHECK_IF_CONNECT_TIME:
            if (connectConfirmMaxTime > connectConfirmTime) {
                connectConfirmTime++;
                TimeoutProcess();
                return false;
            }
            if (!isResetAfterSuccess) {
                SetResult(ERR_WAITING);
            }
            AddLog(stringClass.GetIdsString32806());
            if (isOneTimeBurn != 0) {
                Global::CloseApp(this->result);
            } else {
                ResetByMode();
            }
            return false;
        default:
            return TimerHandleInner();
    }
    return true;
}

bool BurnCtrl::TimerHandleInner()
{
    switch (commonTimerEvent) {
        case TIMER_ID_WAIT_HISILICON:
            SetErrorString(*this, tr("Wait connect success flag timeout."));
            break;
        case TIMER_ID_WAIT_RANDOM:
            SetErrorString(*this, tr("Wait random number timeout."));
            break;
        case TIMER_ID_WAIT_SEC_RESULT:
            SetErrorString(*this, tr("Wait check result timeout."));
            break;
        case TIMER_ID_WAIT_BURN_START_C:
            SetErrorString(*this, tr("Wait start flag (C) timeout."));
            break;
        case TIMER_ID_WAIT_BURN_INIT_ACK:
            SetErrorString(*this, tr("Wait ACK timeout."));
            break;
        case TIMER_ID_WAIT_BURN_INTER_ACK:
            SetErrorString(*this, tr("Sending file timeout."));
            break;
        case TIMER_ID_WAIT_BURN_EOT_C:
            SetErrorString(*this, tr("Wait EOT ACK C timeout."));
            break;
        case TIMER_ID_WAIT_ZERO_ACK:
            SetErrorString(*this, tr("Wait zero ACK timeout."));
            break;
        case TIMER_ID_UPLOAD_COMMON_TIME:
            SetErrorString(*this, tr("Wait next packet timeout."));
            break;
        case TIMER_ID_WAIT_SELOADER_ACK_TIME:
            SetErrorString(*this, tr("Wait SELoader ACK timeout."));
            break;
        case TIMER_ID_WAIT_SELOADER_END_ACK_TIME:
            SetErrorString(*this, tr("Wait SELoader End ACK timeout."));
            TimeoutProcess();
            return false;
        case TIMER_ID_COMPLITE_TIME:
            TimerHandleInnerSub();
            return false;
        default:
            return false;
    }
    return true;
}

void BurnCtrl::TimerHandleInnerSub()
{
    if (chipType == ChipType::WIFI4GCAT1) {
        SetErrorString(*this, stringClass.GetUartBurnMode());
        SetErrorString(*this, stringClass.GetEraseMode().arg(m_eraseModeStr[isEraseMode]));
    }
    SetEditErrorString(IDS_STRING_32879);
    SetErrorString(*this, stringClass.GetIdsString32880());
    SetEditErrorString(IDS_STRING_32879);
    if (isAutoDisconnect) {
        ResetByCmd();
    } else {
        SlotKillAllTimer();
        SetBurnResult(0);
        RecordIntoFile();
    }
}

void BurnCtrl::SlotStartConnectTimerOut()
{
    SendCtrl();
}

void BurnCtrl::StartConnect()
{
    isOpen = true;
    SecureZeroMemory(cDataArray, MAX_BUFFER_LEN);

    SlotKillAllTimer();
    StartConnectSetting();
    sendCtrlCount = 0;
    // 不停打断
    burnCmdIndex = 0;
    if (isOneTimeBurn != 0) {
        QString str = GetFwpkgVersion();
        if (!str.isEmpty()) {
            SetEditErrorString(tr("version:") + str);
        }
        SetEditErrorString(tr("Connecting...Reset the device...\n"));
    }
    if (isResetAfterSuccess) {
        Sleep(SLEEP_TIME_1000);
    }
    SendCtrl();
    if (startConnectTimer == nullptr) {
        startConnectTimer = new QTimer();
    }
    if (startConnectTimer == nullptr) {
        return;
    }
    startConnectTimer->moveToThread(thread);
    if (chipType == ChipType::WIFIDW31) {
        startConnectTimer->setInterval(DW31_START_CONNECT_TIME_OUT_7MS);
    } else {
        startConnectTimer->setInterval(ctrlPeriod);
    }
    startConnectTimer->setTimerType(Qt::PreciseTimer);
    QMetaObject::invokeMethod(startConnectTimer,
                              std::bind(static_cast<void(QTimer::*)()>(&QTimer::start), startConnectTimer));
    connect(startConnectTimer, &QTimer::timeout, this, &BurnCtrl::SlotStartConnectTimerOut, Qt::DirectConnection);
    SetRunningItem(sendCtrlTimerID, this);
    isGetRandomData = false;
}

void BurnCtrl::SetBurnDlg(BurnDlg::BurnDlg *dlg)
{
    burnDlg = dlg;
}

void BurnCtrl::SetSecConn(bool mIsSecConn)
{
    this->isSecConn = mIsSecConn;
}

bool BurnCtrl::IsSecConn() const
{
    return this->isSecConn;
}

bool BurnCtrl::IsBusy()
{
    if (GetBurnFsm() >= HI_BURN_FSM::FSM_BURN_WAIT_START_C
            && GetBurnFsm() < HI_BURN_FSM::FSM_BURN_WAIT_MAX) {
        return true;
    }
    if (GetBurnFsm() >= HI_BURN_FSM::FSM_OPEN_PORT
            && GetBurnFsm() <= HI_BURN_FSM::FSM_WAIT_SEC_RESULT) {
        return true;
    }
    return false;
}

void BurnCtrl::EnterCS()
{
    EnterCriticalSection(&communicationSync);
}

void BurnCtrl::LeaveCS()
{
    LeaveCriticalSection(&communicationSync);
}

void BurnCtrl::EnterCSSend()
{
    EnterCriticalSection(&csSend);
}

void BurnCtrl::LeaveCSSend()
{
    LeaveCriticalSection(&csSend);
}

void BurnCtrl::SetOnlyBurnToolLog(BOOL mOnlyBurnToolLog)
{
    this->onlyBurnToolLog = mOnlyBurnToolLog;
}

void BurnCtrl::EnterCSEdit()
{
    EnterCriticalSection(&csEdit);
}

void BurnCtrl::LeaveCSEdit()
{
    LeaveCriticalSection(&csEdit);
}

void BurnCtrl::SetForceReadFlag(BOOL isForceRead)
{
    this->isForceReadWithSleep = isForceRead;
}

bool BurnCtrl::GetForceReadFlag() const
{
    return isForceReadWithSleep;
}

void BurnCtrl::SetResultByOwnerFlag(BOOL mIsResultByOwner)
{
    this->isResultByOwner = mIsResultByOwner;
}

void BurnCtrl::SetForceReadTime(UINT mForceReadTime)
{
    this->forceReadTime = mForceReadTime;
}

unsigned int BurnCtrl::GetForceReadTime() const
{
    return forceReadTime;
}

void BurnCtrl::SetConfirmConnectSleepTime(UINT time)
{
    connectConfirmSleepTimeout = time;
}

void BurnCtrl::SetConfirmConnectWaitTime(UINT time)
{
    connectConfirmWaitTimeout = time;
}

void BurnCtrl::SetPeriod(int period)
{
    ctrlPeriod = period;
}

void BurnCtrl::SwitchBoot(BootType type)
{
    this->bootType = type;
}

void BurnCtrl::YmodemNextPacket()
{
    int pktLen = 1029; // 1029长度
    PBYTE pBurnFile = new unsigned char[pktLen]();
    if (pBurnFile == nullptr) {
        return;
    }
    SecureZeroMemory(pBurnFile, pktLen);
    pBurnFile[0] = MODEM_STX;
    pBurnFile[1] = pkgNum;
    pBurnFile[2] = 0xff - pkgNum; // 第2字节固定含义
    pkgNum++;
    UINT nBytesRead = 0;
    if (IsEncrypt()) {
        nBytesRead = memoryOperation.Read(pBurnFile + 3, 1024); // 读1024字节到偏移3字节之后
    } else {
        nBytesRead = binFile.read(reinterpret_cast<CHAR*>(pBurnFile + 3), 1024);  // 读1024字节到偏移3字节之后
    }
    WORD crc = YModemClass::YModem::GetCrc(&(pBurnFile[3]), 1024);                // 计算1024字节crc从第3字节开始
    pBurnFile[1027] = static_cast<unsigned char>(crc >> 8);           // crc右移8位放在1027上
    pBurnFile[1028] = static_cast<unsigned char>(crc);                // crc低位放在1028位
    WriteToPort(reinterpret_cast<char *>(pBurnFile), pktLen);
    delete[] pBurnFile;
    UpdateProgress(progressPos++);
    isProcessOk = true;
    if (nBytesRead < 1024) { // 长度1024字节
        SetFsm(HI_BURN_FSM::FSM_BURN_WAIT_FINAL_ACK);
    } else {
        SetFsm(HI_BURN_FSM::FSM_BURN_WAIT_INTER_ACK);
    }
    SetTimerByFsm();
}

void BurnCtrl::SetFilePath(int index, QString strPath)
{
    strFilePathArray[index] = strPath;
}

QString BurnCtrl::GetFilePath()
{
    if (strFilePathArray.size() == 0) {
        return "";
    }
    if (filePathIndex >= strFilePathArray.size()) {
        filePathIndex = 0;
    }
    QString strTmp = strFilePathArray[filePathIndex];
    filePathIndex++;
    return strTmp;
}

void BurnCtrl::StartUpload(QString output, U32 addr, U32 size) {}

void BurnCtrl::ReadEfuse(U32 addr, U32 size) {}

void BurnCtrl::SetEraseMode(int eraseMode) {}

void BurnCtrl::SetOnlyEraseAll(bool eraseAll)
{
}

void BurnCtrl::ResetByCmd()
{
}

void BurnCtrl::AtReset(QString)
{
}
void BurnCtrl::SwitchToDfu()
{
}

void BurnCtrl::EraseAllByCmd() {}

void BurnCtrl::SetBurnTimeout(UINT timeout)
{
    this->sendBurnTimeout = timeout;
}

void BurnCtrl::SetResult(unsigned int mResult)
{
    this->result = mResult;
    AddLog(stringClass.GetIdsString32845() + QString::number(this->result));
    NotifyState(NOTIFY_TYPE_RESULT, this->result);
    if (this->result != ERR_DOING && this->result != ERR_WAITING) {
        SetBurnEndTime(GetBurnCurrentTime());
        SetBurnResult(this->result);
        RecordIntoFile();
    }
    if (independent) {
        ShowResult();
        return;
    }
    if (this->result == ERR_WAITING) {
        if (isResultByOwner) {
            return;
        }
    }
    ShowResult();
}

void BurnCtrl::ShowResult()
{
    if (!isMultipleBurn) {
        return;
    }
    EnterCSEdit();
    if (result == 0) {
        QTextCharFormat fmt;
        fmt.setBackground(COLOR_RGB_VALUE_GREEN);
        fmt.setForeground(COLOR_RGB_VALUE_WHITE);
        MergeCurrentCharFormat(fmt);
        InsertPlainText(tr("Pass"));
    } else if (result == ERR_DOING) {
        QTextCharFormat fmt;
        fmt.setBackground(COLOR_RGB_VALUE_YELLOW);
        fmt.setForeground(COLOR_RGB_VALUE_BLACK);
        MergeCurrentCharFormat(fmt);
        InsertPlainText(tr("Doing"));
    } else if (result == ERR_WAITING) {
        QTextCharFormat fmt;
        fmt.setBackground(COLOR_RGB_VALUE_WHITE);
        fmt.setForeground(COLOR_RGB_VALUE_BLACK);
        MergeCurrentCharFormat(fmt);
        InsertPlainText(tr("Waiting"));
    } else if (result == ERR_USB_IOERR) {
    } else {
        QTextCharFormat fmt;
        fmt.setBackground(COLOR_RGB_VALUE_RED);
        fmt.setForeground(COLOR_RGB_VALUE_WHITE);
        MergeCurrentCharFormat(fmt);
        InsertPlainText(tr("Fail"));
    }
    LeaveCSEdit();
}

void BurnCtrl::SetResultFromAToB(unsigned int resultA, unsigned int resultB)
{
    if (result == resultA) {
        result = resultB;
        QString strLog;
        AddLog("set result from a to b" + QString::number(result));
        NotifyState(NOTIFY_TYPE_RESULT, result);
        ShowResult();
        ResetByMode();
    }
}

unsigned int BurnCtrl::GetResult() const
{
    return result;
}

BurnCtrl::BurnCmdType BurnCtrl::GetCurrentCmdType()
{
    if (burnCmdTypeArray.size() <= 0 || burnCmdIndex >= burnCmdTypeArray.size()) {
        return BurnCmdType::UNKNOWN;
    }
    return burnCmdTypeArray[burnCmdIndex];
}

QString BurnCtrl::GetCurrentFilePath()
{
    if (strFilePathArray.size() <= 0 || burnCmdIndex >= burnCmdTypeArray.size()) {
        return "";
    }
    return strFilePathArray[burnCmdIndex];
}

void BurnCtrl::SetTimerByFsm()
{
    BurnCtrlTimer::TimerInfo *point = nullptr;
    U32 timeout = Global::timerIdWaitCommonTimeout;
    bool isPeriod = 0;
    if (!MakeTimerInfoByFsm(timeout, isPeriod)) {
        return;
    }
    if (commonTimer == nullptr) {
        commonTimer = new QTimer();
    }
    if (commonTimer == nullptr) {
        return;
    }
    if (isExactTimer) {
        connect(commonTimer, &QTimer::timeout, this, &BurnCtrl::SlotBurnCtrlCommonTimerHandler2,
                Qt::DirectConnection);
    } else {
        connect(commonTimer, &QTimer::timeout, this, &BurnCtrl::SlotBurnCtrlCommonTimerHandlerTest,
                Qt::DirectConnection);
    }
    commonTimer->moveToThread(thread);
    commonTimer->setInterval(timeout);
    commonTimer->setTimerType(Qt::PreciseTimer);
    commonTimer->setSingleShot(!isPeriod);
    QMetaObject::invokeMethod(commonTimer,
                              std::bind(static_cast<void(QTimer::*)()>(&QTimer::start), commonTimer));
    commonTimerID = commonTimer->timerId();

    SetParamPoint(commonTimerID, point);
    SetRunningItem(commonTimerID, this);
}

bool BurnCtrl::MakeTimerInfoByFsm(U32& timeout, bool& isPeriod)
{
    switch (fsm) {
        case HI_BURN_FSM::FSM_BURN_WAIT_SELOADR_END_ACK:
            commonTimerEvent = TIMER_ID_WAIT_SELOADER_END_ACK_TIME;
            timeout = Global::timerIdWaitCommonTimeout;
            break;
        case HI_BURN_FSM::FSM_BURN_UPLOAD_EOT_C:
        case HI_BURN_FSM::FSM_BURN_UPLOAD_END_ACK:
            commonTimerEvent = TIMER_ID_UPLOAD_COMMON_TIME;
            timeout = Global::timerIdWaitCommonTimeout;
            break;
        case HI_BURN_FSM::FSM_BURN_UPLOAD_INIT_ACK:
            commonTimerEvent = TIMER_ID_UPLOAD_RETRY_TIME;
            timeout = TIMEOUT;
            isPeriod = true;
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_ZERO_ACK:
            commonTimerEvent = TIMER_ID_WAIT_ZERO_ACK;
            timeout = Global::timerIdWaitShortTimeout;
            break;
        case HI_BURN_FSM::FSM_CHECK_IF_CONNECT:
            commonTimerEvent = TIMER_ID_CHECK_IF_CONNECT_TIME;
            timeout = connectConfirmWaitTimeout;
            break;
        case HI_BURN_FSM::FSM_WORK:
            commonTimerEvent = TIMER_ID_COMPLITE_TIME;
            timeout = Global::timerIdCompliteTimeout;
            break;
        default:
            return MakeTimerInfoByFsmInner(timeout);
    }
    return true;
}

bool BurnCtrl::MakeTimerInfoByFsmInner(U32& timeout)
{
    switch (fsm) {
        case HI_BURN_FSM::FSM_WAIT_INTERRUPT_FLAG:
            commonTimerEvent = TIMER_ID_WAIT_INTERRUPT_FLAG;
            timeout = Global::timerIdWaitInterruptFlagTimeout;
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_START_C:
            commonTimerEvent = TIMER_ID_WAIT_BURN_START_C;
            timeout = Global::timerIdWaitShortTimeout;
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_SELOADR_UPLOAD_ACK:
            commonTimerEvent = TIMER_ID_UPLOAD_COMMON_TIME;
            timeout = Global::timerIdWaitCommonTimeout;
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_SELOADR_READ_EFUSE_ACK:
            commonTimerEvent = TIMER_ID_WAIT_SELOADER_ACK_TIME;
            timeout = Global::timerIdWaitCommonTimeout;
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_SELOADR_DOWN_ACK:
            commonTimerEvent = TIMER_ID_WAIT_SELOADER_ACK_TIME;
            timeout = Global::timerIdWaitLongTimeout;
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_SELOADR_RESET_ACK:
        case HI_BURN_FSM::FSM_BURN_WAIT_SELOADR_LOCK_ACK:
            commonTimerEvent = TIMER_ID_WAIT_SELOADER_ACK_TIME;
            timeout = Global::timerIdWaitCommonTimeout;
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_INIT_ACK:
            commonTimerEvent = TIMER_ID_WAIT_BURN_INIT_ACK;
            timeout = Global::timerIdWaitShortTimeout;
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_FINAL_ACK:
        case HI_BURN_FSM::FSM_BURN_WAIT_INTER_ACK:
            commonTimerEvent = TIMER_ID_WAIT_BURN_INTER_ACK;
            timeout = Global::timerIdWaitShortTimeout;
            break;
        case HI_BURN_FSM::FSM_WAIT_RANDOM:
            commonTimerEvent = TIMER_ID_WAIT_RANDOM;
            timeout = TIMER_ID_WAIT_RANDOM_3921_TIMEOUT;
            break;
        case HI_BURN_FSM::FSM_BURN_WAIT_EOT_C:
            commonTimerEvent = TIMER_ID_WAIT_BURN_EOT_C;
            timeout = Global::timerIdWaitShortTimeout;
            break;
        default:
            return false;
    }
    return true;
}

void BurnCtrl::SetFsm(HI_BURN_FSM mFsm)
{
    this->fsm = mFsm;
    NotifyState(static_cast<int>(mFsm), 0xffffffff);
}

void BurnCtrl::UpdateProgress(UINT progress)
{
    SetProgressValue(progress);
    NotifyState(static_cast<int>(fsm), progress);
}

void BurnCtrl::SetProgressValue(unsigned int progress)
{
    emit SignalSetProgressValue(progress);
}

void BurnCtrl::SetProgressRange() {}

void BurnCtrl::NotifyState(UINT ret, UINT progress)
{
    emit SignalNotifyState(ret, progress);
}

void BurnCtrl::WifiState()
{
    emit SignalAutoDisconnect(0, 0);
}

void BurnCtrl::ResetByMode()
{
    if (isAutoBurn && isMultipleBurn) {
        ResetBurnState();
        StartConnect();
    } else {
        ResetBurnState();
    }
}

void BurnCtrl::SetOneTimeBurnFlag(bool mIsOneTimeBurn)
{
    this->isOneTimeBurn = mIsOneTimeBurn;
}

void BurnCtrl::SetAutoBurnFlag(bool mIsAutoBurn)
{
    this->isAutoBurn = mIsAutoBurn;
}

void BurnCtrl::SetLoaderDfu(bool mIsLoaderDfu)
{
    this->isLoaderDfu = mIsLoaderDfu;
}

void BurnCtrl::SetIsAutoDfu(DfuBurnMode mode)
{
    this->dfuMode = mode;
}

void BurnCtrl::SetUsbDeviceInfo(HidDeviceInfo usbDeviceInfo)
{
    this->deviceInfo = usbDeviceInfo;
}

void BurnCtrl::SetIPAddress(const QString &ip)
{
    this->ipAddress = ip;
}

void BurnCtrl::SetBoardIPAddress(const IPInfo &ipinfo)
{
    this->ipInfo = ipinfo;
}

void BurnCtrl::SetAutoDisconnectFlag(bool mIsAutoDisconnect)
{
    this->isAutoDisconnect = mIsAutoDisconnect;
}

void BurnCtrl::SetReopenComFlag(bool mIsReopenCom)
{
    this->isReopenCom = mIsReopenCom;
}

void BurnCtrl::SetIsEncrypt(bool mIsEncrypt)
{
    this->isEncrypt = mIsEncrypt;
}

void BurnCtrl::SetEncryptBuffer(BYTE *buffer)
{
    this->encryptBuffer = buffer;
}

void BurnCtrl::SetEncryptBufferLen(DWORD bufferLen)
{
    this->encryptBufferLen = bufferLen;
}

void BurnCtrl::SetReadEfuse(bool mReadEfuse)
{
    this->readEfuse = mReadEfuse;
}

void BurnCtrl::SetStartBit(QString mStartBit)
{
    this->startBit = mStartBit;
}

void BurnCtrl::SetBitWidth(QString mBitWidth)
{
    this->bitWidth = mBitWidth;
}

void BurnCtrl::SetPackageSize(UINT packageSize)
{
    modemPacketSize = packageSize;
    modemPacketSizeBackup = packageSize;
}

void BurnCtrl::SetHSANTypeFlag(QString type)
{
}

void BurnCtrl::SetFileInfo(QString mtSrFilePath)
{
    this->strFilePath = mtSrFilePath;
    QFileInfo fileInfo(this->strFilePath);
    this->strFileName = fileInfo.fileName();
    fileSize = fileInfo.size();
    strFileSize = QString::number(fileSize);
}

void BurnCtrl::SetMultiBurnFlag()
{
    burnflag = true;
}

bool BurnCtrl::StartWiteMonitoring()
{
    worker = new BurnCtrlWorker();
    if (thread == nullptr) {
        thread = new MyThreadClass::MyThread();
    }
    if (worker == nullptr) {
        return false;
    }

    worker->moveToThread(thread);
    worker->SetWiteThreadMsgId(witeThreadMsgId);
    connect(thread, &QThread::finished, worker, &QObject::deleteLater);
    if (isOneTimeBurn != 0) {
        connect(CmdCtrl::GetInstence(), &CmdCtrl::SignalSendMsg, worker, &BurnCtrlWorker::SlotSendMsg);
    } else if (burnDlg != nullptr) {
        connect(burnDlg, &BurnDlg::BurnDlg::SignalSendMsgInBurnDlg, worker, &BurnCtrlWorker::SlotSendMsg);
    }
    connect(this, &BurnCtrl::SignalSendMsg, worker, &BurnCtrlWorker::SlotSendMsg, Qt::QueuedConnection);
    if (port.GetSerialport() != nullptr) {
        connect(port.GetSerialport(), &PortBase::SignalSendMsg, worker, &BurnCtrlWorker::SlotSendMsg);
    }
    if (port.GetTcpPort() != nullptr) {
        connect(port.GetTcpPort(), &PortBase::SignalSendMsg, worker, &BurnCtrlWorker::SlotSendMsg);
    }
    connect(worker, &BurnCtrlWorker::SignalCommunication, this, &BurnCtrl::SlotCommunication, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalKillAllTimer, this, &BurnCtrl::SlotKillAllTimer, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalResetUIAndFSM, this, &BurnCtrl::SlotResetUIAndFSM, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalInitBurnCmd, this, &BurnCtrl::SlotInitBurnCmd, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalStartConnect, this, &BurnCtrl::SlotStartConnect, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalResetBurnState, this, &BurnCtrl::SlotResetBurnState, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalSetResult, this, &BurnCtrl::SlotSetResult, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalShowResult, this, &BurnCtrl::SlotShowResult, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalSetResultFromAToB,
            this, &BurnCtrl::SlotSetResultFromAToB, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalExitApp, this, &BurnCtrl::SlotExitApp, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalCloseJlink, this, &BurnCtrl::SlotCloseJlink, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalExport, this, &BurnCtrl::SlotExport, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalCommonAction1, this, &BurnCtrl::SlotCommonAction1, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalCommonAction2, this, &BurnCtrl::SlotCommonAction2, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalCommonAction3, this, &BurnCtrl::SlotCommonAction3, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalEraseAll, this, &BurnCtrl::SlotEraseAll, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalMcuReopen, this, &BurnCtrl::SlotMcuReopen, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalStartBurn, this, &BurnCtrl::SlotStartBurn, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalErase, this, &BurnCtrl::SlotEraseMemory, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalGetParameter, this, &BurnCtrl::SlotGetParameter, Qt::DirectConnection);
    connect(worker, &BurnCtrlWorker::SignalSetParameter, this, &BurnCtrl::SlotSetParameter, Qt::DirectConnection);

    thread->start();
    isWiteThreadAlive = true;
    return true;
}


DWORD BurnCtrl::GetWiteThreadId() const
{
    return witeThreadId;
}

bool BurnCtrl::IsNeedRetry() const
{
    if (retryTime < MAX_RETRY_TIME) {
        return true;
    } else {
        return false;
    }
}

void BurnCtrl::SendRetryFlag()
{
    char buff = MODEM_NAK;
    WriteToPort(&buff, 1);
    retryTime++;
}

void BurnCtrl::SetUseExactTimer(BOOL useExactTimer)
{
    this->isExactTimer = useExactTimer;
}

void BurnCtrl::TimeoutProcess()
{
}

unsigned int BurnCtrl::AddLogToBuffer(const QString &inputLog) const
{
    Q_UNUSED(inputLog);
    return 0;
}

unsigned int BurnCtrl::AddLog(QString input) const
{
    QDateTime t;
    QString strLog = "[COM" + QString::number(com) + "] " + t.currentDateTime().toString("yyyy-MM-dd hh:mm:ss");

    RMDA_TIME_STRU currtUpgTime;
    currtUpgTime.GetHostDateTime();
    strLog += input;
    strLog += IDS_STRING_32824;
    AddLogToBuffer(strLog);
    return 0;
}

BootType BurnCtrl::GetBootType() const
{
    return bootType;
}

int BurnCtrl::GetPeriod() const
{
    return ctrlPeriod;
}

UINT BurnCtrl::GetConnectConfirmSleepTimeout() const
{
    return connectConfirmSleepTimeout;
}

UINT BurnCtrl::GetConnectConfirmWaitTimeout() const
{
    return connectConfirmWaitTimeout;
}

U32 BurnCtrl::GetMultiBurnTotalNum() const
{
    return totalNum;
}

U32 BurnCtrl::GetMultiBurnNumPerLine() const
{
    return numPerLine;
}

bool BurnCtrl::GetMultiBurnIndenpendentBurn() const
{
    return independent;
}

bool BurnCtrl::GetMultiBurnReopenCom() const
{
    return isReopenCom;
}

void BurnCtrl::SetMultiBurnTotalNum(unsigned int mTotalNum)
{
    this->totalNum = mTotalNum;
}

void BurnCtrl::SetMultiBurnNumPerLine(unsigned int mNumPerLine)
{
    this->numPerLine = mNumPerLine;
}

void BurnCtrl::SetMultiBurnIndenpendentBurn(bool indenpendent)
{
    this->independent = indenpendent;
}

void BurnCtrl::SetResetAfterBurn(bool reset)
{
    this->isReset = reset;
}

void BurnCtrl::SetExportAfterBurn(bool mIsExport)
{
    this->isExport = mIsExport;
}

void BurnCtrl::SetExportPath(QString mExportTarget)
{
    this->exportTarget = mExportTarget;
}

void BurnCtrl::SetExportAddr(QString mExportAddr)
{
    this->exportAddr = mExportAddr;
}

void BurnCtrl::SetExportSize(QString mExportSize)
{
    this->exportSize = mExportSize;
}

void BurnCtrl::SetIsResetAfterSuccess(bool mIsResetAfterSuccess)
{
    this->isResetAfterSuccess = mIsResetAfterSuccess;
}

bool BurnCtrl::GetIsResetAfterSuccess() const
{
    return this->isResetAfterSuccess;
}

void BurnCtrl::SetIsSwitchAfterLoader(bool mIsSwitchAfterLoader)
{
    this->isSwitchAfterLoader = mIsSwitchAfterLoader;
}

bool BurnCtrl::GetIsSwitchAfterLoader() const
{
    return this->isSwitchAfterLoader;
}

void BurnCtrl::SetUSBSerialName(const QString& mSerialName)
{
    emit SignalAddSerialNum(mSerialName);
}

void BurnCtrl::SetIsEmptyFlash(bool)
{
}

void BurnCtrl::SetEraseConfig(unsigned int cbEraseConfig, const QVector<EraseConfig> &vecErase)
{
    eraseConfig = cbEraseConfig;
    vecEraseConfig = vecErase;
}

void BurnCtrl::SetYModemEachPackageSize(int packageSize)
{
    modemPacketSize = packageSize;
    modemPacketSizeBackup = packageSize;
}

unsigned int BurnCtrl::GetYModemEachPackageSize() const
{
    return modemPacketSizeBackup;
}

long int BurnCtrl::SlotCommunication(WPARAM srcData, LPARAM srcLen)
{
    PBYTE data = reinterpret_cast<PBYTE>(srcData);
    
    if (srcLen > 0) {
        delete[] data; // 释放异步传入的原始数据内存
    }
    return 0;
}

void BurnCtrl::SlotSetResult(WPARAM srcData)
{
    unsigned int data = static_cast<unsigned int>(srcData);
    SetResult(data);
}

void BurnCtrl::SlotShowResult()
{
    ShowResult();
}

BurnCtrl *BurnCtrl::GetRunningItem(UINT id)
{
    csLock.EntryCS();
    BurnCtrl *ret = sendCtrlTimerToPoint[id];
    csLock.LeaveCs();
    return ret;
};

void BurnCtrl::RemoveRunningItem(UINT id)
{
    csLock.EntryCS();
    sendCtrlTimerToPoint.remove(id);
    csLock.LeaveCs();
};

void BurnCtrl::SetRunningItem(UINT id, BurnCtrl *point)
{
    csLock.EntryCS();
    sendCtrlTimerToPoint[id] = point;
    csLock.LeaveCs();
};

void BurnCtrl::RemoveParamPoint(UINT id)
{
    csLock.EntryCS();
    if (timerToParam.find(id) != timerToParam.end()) {
        auto ret = timerToParam[id];
        if (ret != nullptr) {
            delete ret;
        }
        timerToParam.remove(id);
    }
    csLock.LeaveCs();
}

void BurnCtrl::SetParamPoint(UINT id, const BurnCtrlTimer::TimerInfo *point)
{
    csLock.EntryCS();
    timerToParam[id] = point;
    csLock.LeaveCs();
}

void BurnCtrl::SetIsWiteThreadAlive(bool mIsWiteThreadAlive)
{
    this->isWiteThreadAlive = mIsWiteThreadAlive;
}

void BurnCtrl::SlotResetUIAndFSM()
{
    ResetUIAndFSM();
}

void BurnCtrl::SlotInitBurnCmd()
{
    InitBurnCmd();
}

void BurnCtrl::SlotStartConnect()
{
    StartConnect();
}

void BurnCtrl::SlotResetBurnState()
{
    ResetBurnState();
}

void BurnCtrl::SlotConfigComPort()
{
    ConfigComPort();
}

void BurnCtrl::BurnCtrlCancel()
{
}

BurnCtrlWorker *BurnCtrl::GetBurnCtrlWorker()
{
    return worker;
}

void BurnCtrl::SlotSetResultFromAToB(WPARAM wParam, LPARAM lParam)
{
    SetResultFromAToB(static_cast<unsigned int>(wParam), static_cast<unsigned int>(lParam));
}

void BurnCtrl::SlotExitApp(WPARAM wParam, LPARAM lParam) const
{
    if (lParam != sizeof (UINT)) {
        return;
    }
    Sleep(SLEEP_TIME_500);
    UINT errorNum = static_cast<UINT>(wParam);
    Global::CloseApp(errorNum);
    return;
}

void BurnCtrl::SlotCloseJlink()
{
}

void BurnCtrl::SetIsCancel(BOOL mIsCancel)
{
    this->isCancel = mIsCancel;
}

void BurnCtrl::SetIsFirstBurnStart(bool firstBurnStart)
{
    this->isFirstBurnStart = firstBurnStart;
}

void BurnCtrl::SlotExport(WPARAM wParam, LPARAM lParam)
{
}

void BurnCtrl::SlotCommonAction1()
{
    CommonAction1();
}

void BurnCtrl::SlotCommonAction2()
{
    CommonAction2();
}

void BurnCtrl::SlotCommonAction3()
{
    CommonAction3();
}

void BurnCtrl::SlotEraseAll()
{
    EraseAll();
}

void BurnCtrl::SlotMcuReopen()
{
    McuReopen();
}

void BurnCtrl::McuReopen()
{
}

void BurnCtrl::SlotStartBurn()
{
    StartBurn();
}

void BurnCtrl::EraseAll()
{
}

void BurnCtrl::CommonAction1()
{
}

void BurnCtrl::CommonAction2()
{
}

void BurnCtrl::CommonAction3()
{
}

void BurnCtrl::DisconnectSignalSendMsg() const
{
}

void BurnCtrl::ConnectSignalSendMsg() const
{
}

bool BurnCtrl::IsEncrypt() const
{
    return (isEncrypt && (encryptBuffer != nullptr) && (encryptBufferLen != 0));
}

MemoryOperation::MemoryOperation()
    : encryptBuffer(nullptr),
      encryptBufferLen(0),
      offset(0)
{
}

MemoryOperation::~MemoryOperation()
{
    encryptBuffer = nullptr;
}

bool MemoryOperation::Seek(qint64 mOffset)
{
    if (offset > encryptBufferLen) {
        return false;
    }
    this->offset = mOffset;
    return true;
}

qint64 MemoryOperation::Pos() const
{
    return offset;
}

qint64 MemoryOperation::Read(BYTE *data, qint64 maxlen)
{
    if (offset + maxlen > encryptBufferLen) {
        errno_t retMemcpy = memcpy_s(data, encryptBufferLen - offset,
            encryptBuffer + offset, encryptBufferLen - offset);
        if (retMemcpy != 0) {
            printf("Error memcpy");
        }
        return encryptBufferLen - offset;
    }
    errno_t retMemcpy = memcpy_s(data, maxlen, encryptBuffer + offset, maxlen);
    if (retMemcpy != 0) {
        printf("Error memcpy");
    }
    offset += maxlen;
    return maxlen;
}

void MemoryOperation::SetEncrypt(BYTE *buffer, DWORD bufferLen)
{
    this->encryptBuffer = buffer;
    this->encryptBufferLen = bufferLen;
    offset = 0;
}
void MemoryOperation::Init()
{
    this->encryptBuffer = nullptr;
    this->encryptBufferLen = 0;
    offset = 0;
}

QString BurnCtrl::GetBurnCurrentTime() const
{
    return QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss");
}

QString BurnCtrl::GetBurnComToStr() const
{
    return "COM" + QString::number(com);
}

QMap<int, BIN_INFO> BurnCtrl::GetBurnArray()
{
    return infoArray;
}

void BurnCtrl::SetBurnFileName(QString mStrFileName) const
{
    if (optLog != nullptr) {
        optLog->SetBurnFileName(mStrFileName);
    }
}

void BurnCtrl::SetBurnStartTime(QString strSartTime) const
{
    if (optLog != nullptr) {
        optLog->SetBurnStartTime(strSartTime);
    }
}

void BurnCtrl::SetBurnEndTime(QString strEndTime) const
{
    if (optLog != nullptr) {
        optLog->SetBurnEndTime(strEndTime);
    }
}

void BurnCtrl::SetBurnComNum(QString strComNum) const
{
    if (optLog != nullptr) {
        optLog->SetBurnComNum(strComNum);
    }
}

void BurnCtrl::SetBurnBinFile(QMap<int, BIN_INFO> mInfoArray) const
{
    QStringList strList;
    for (int i = 0; i < mInfoArray.size(); i++) {
        strList.push_back(mInfoArray[i].fileName);
    }
    if (optLog != nullptr) {
        optLog->SetBurnBinFile(strList);
    }
}

void BurnCtrl::RecordIntoFile() const
{
    if (optLog != nullptr) {
        optLog->RecordIntoFile();
    }
}

void BurnCtrl::RecordFile(QByteArray str) const
{
    if (optLog != nullptr) {
        optLog->RecordFile(str);
    }
}

void BurnCtrl::SetBurnResult(int mResult) const
{
    if (optLog != nullptr) {
        optLog->SetBurnResult(mResult);
    }
}

void BurnCtrl::CloseFile() const
{
    if (optLog != nullptr) {
        optLog->CloseFile();
    }
}

void BurnCtrl::SetChipModel(int mChipModel)
{
    this->chipModel = mChipModel;
}

void BurnCtrl::SetMcuConfig(McuConfig mMcuConfig)
{
    this->mcuConfig = mMcuConfig;
}

void BurnCtrl::SetTransmissionMode(int mode)
{
    this->transmissionMode = mode;
}

void BurnCtrl::SetJtagSwd(McuJtagSwd mcuJtagSwd)
{
    this->mcuJtagSwdPath = mcuJtagSwd;
}

void BurnCtrl::SetChipId(McuChipId mcuChipId)
{
    this->mcuChipIdInfo = mcuChipId;
}

void BurnCtrl::SetMainStartAddress(MainStartAddrInfo info)
{
    this->mainStartAddrInfo = info;
}

void BurnCtrl::SetSramAddrInfo(SramAddrInfo info)
{
    this->sramAddrInfo = info;
}

void BurnCtrl::SetBurnPath(QString path)
{
    this->burnPath = path;
}

void BurnCtrl::SetInfoStartAddress(int info)
{
    this->infoStartAddress = info;
}

void BurnCtrl::RmoveTimerKey()
{
    if (commonTimer != nullptr) {
        QMetaObject::invokeMethod(commonTimer,
                                  std::bind(static_cast<void(QTimer::*)()>(&QTimer::stop), commonTimer),
                                  Qt::DirectConnection);
        delete commonTimer;
        commonTimer = nullptr;
    }

    if (commonTimerID != 0) {
        RemoveRunningItem(commonTimerID);
        RemoveParamPoint(commonTimerID);
        commonTimerID = 0;
    }
}

void BurnCtrl::SetIsReadBack(bool readBack)
{
    this->isReadBack = readBack;
}

void BurnCtrl::SetIsRun(bool run)
{
    this->isRun = run;
}

void BurnCtrl::SlotEraseMemory(WPARAM data, LPARAM len)
{
}

void BurnCtrl::SlotGetParameter()
{
}

void BurnCtrl::SlotSetParameter()
{
}

void BurnCtrl::SetTotalDigits(int)
{
}

void BurnCtrl::SetParamStartAddress(ulong)
{
}

void BurnCtrl::SetProtectionPara(ParameterInfo)
{
}
void BurnCtrl::SetIsInfoPart(bool)
{
}

void BurnCtrl::SetInfoArea(int)
{
}

void BurnCtrl::SetParameterInfoList(const QList<ParameterInfo> &,
                                    const QList<ParameterInfo> &,
                                    const QList<ParameterBuff> &)
{
}

void BurnCtrl::SetParameterSaveInfo(const QString &, ulong)
{
}

void BurnCtrl::SetIsParameterReset(bool)
{
}

void BurnCtrl::FwpkgVersion(QString version)
{
    fwpkgVersion = version;
}


QString BurnCtrl::GetFwpkgVersion()
{
    return fwpkgVersion;
}
